#!/bin/bash

# -------------------------------------------------------------------------- #
# Copyright 2002-2023, OpenNebula Project, OpenNebula Systems                #
#                                                                            #
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
# not use this file except in compliance with the License. You may obtain    #
# a copy of the License at                                                   #
#                                                                            #
# http://www.apache.org/licenses/LICENSE-2.0                                 #
#                                                                            #
# Unless required by applicable law or agreed to in writing, software        #
# distributed under the License is distributed on an "AS IS" BASIS,          #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
# See the License for the specific language governing permissions and        #
# limitations under the License.                                             #
#--------------------------------------------------------------------------- #

# Parameters are times (seconds) and monitoring command (or function).
# Executes monitoring command until it is successful (VM is no longer
# running) or the timeout is reached.
function retry
{
    # Disable exit on error
    set +e

    times=$1
    function=$2

    count=1

    ret=$($function)
    error=$?

    while [ $count -lt $times -a "$error" != "0" ]; do
        sleep 1
        count=$(( $count + 1 ))
        ret=$($function)
        error=$?
    done

    # enable exit on error back
    set -e
    [ "x$error" = "x0" ]
}

# exit when any command fails
set -e

CGROUP_PATH=""
VM_NAME=""
CGROUP_TO=60
ONLY_UMOUNT=""

while getopts ":c:v:t:o" opt; do
    case $opt in
        c) CGROUP_PATH="$OPTARG" ;;
        v) VM_NAME="$OPTARG" ;;
        t) CGROUP_TO=$OPTARG ;;
        o) ONLY_UMOUNT="1"
    esac
done

shift $(($OPTIND - 1))

# Check $CGROUP_PATH is an existing directory
if [ ! -d "$CGROUP_PATH" ]; then
    exit -1
fi

# Check $VM_NAME have the right format
regex='^one-[0-9]+$'
if ! [[ "$VM_NAME" =~ $regex ]]; then
    exit -1
fi

# Check $CGROUP_TO is an integer
regex_num='^[0-9]+$'
if ! [[ "$CGROUP_TO" =~ $regex_num ]]; then
    exit -1
fi

ROOTFS_PATH="/srv/jailer/firecracker/$VM_NAME/root"

# Remove Firecracker residual files
rm -rf "$ROOTFS_PATH/dev"
rm -rf "$ROOTFS_PATH/run"
rm -f "$ROOTFS_PATH/firecracker"

# Unmount VM directory (if needed)
if  grep -qs "$ROOTFS_PATH" /proc/mounts; then
    umount "$ROOTFS_PATH"
fi

#-------------------------------------------------------------------------------
# Wait for a cgroup to not being used
#   @param $1 - Path to cgroup
#-------------------------------------------------------------------------------
function wait_cgroup () {
    t_start=$(date +%s)

    while [ $(($(date +%s)-$t_start)) -lt $CGROUP_TO ] &&
          [ ! -z "$(cat $1/tasks)" ] &&
          [ ! -z "$(lsof $1)" ]; do continue; done
}

function clean_cgroups () {
    DIR="$CGROUP_PATH/cpu/firecracker/$VM_NAME"
    wait_cgroup $DIR
    if [ -d "$DIR" ]; then rmdir "$DIR"; fi

    DIR="$CGROUP_PATH/cpuset/firecracker/$VM_NAME"
    wait_cgroup $DIR
    if [ -d "$DIR" ]; then rmdir "$DIR"; fi

    DIR="$CGROUP_PATH/pids/firecracker/$VM_NAME"
    wait_cgroup $DIR
    if [ -d "$DIR" ]; then rmdir "$DIR"; fi
}

retry 3 clean_cgroups

#-------------------------------------------------------------------------------
# Remove VM chroot directory
#-------------------------------------------------------------------------------
if [ -n "${ONLY_UMOUNT}" ]; then
    exit 0
fi

rm -rf $(dirname $ROOTFS_PATH)

exit 0
